/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http:  // www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "tecsun_adaptor.h"
#include <plugin.h>
#include <libusb/libusb.h>
#include <memory>
#include <string>
#include <vector>
#include <fcntl.h>
#include "iccreader_hilog.h"
#include "Reader.h"
#include "sscarddriver.h"
#include "charset.h"

using namespace SwanLink::Finance;

#define CHECK_STATUS(cond, status) do {\
    if ((cond)) {\
        m_iStatus = SUCCESS;\
    } else {\
        m_iStatus = status;\
        return m_iStatus;\
    }\
}while(0)

#define CHECK_STATUS_NO_RET(cond, status) do {\
    if ((cond)) {\
        m_iStatus = SUCCESS;\
    } else {\
        m_iStatus = status;\
        return;\
    }\
}while(0)

// 卡座号
#define CARD_MAIN 0x01  // 主卡座
#define CARD_PSAM1 0x11  // PSAM1；
#define CARD_PSAM2 0x12  // PSAM2；
#define CARD_NOTOUCH 0x31  // 非接卡

int ConvertStat(int status) {
    switch (status) {
    case IFD_ICC_TypeError:  //           -1
        return ERR_ICC_TypeError;
    case IFD_ICC_NoExist:  //             -2
        return ERR_ICC_NoExist;
    case IFD_ICC_NoPower:  //             -3
        return ERR_ICC_NoPower;
    case IFD_ICC_NoResponse:  //          -4
        return ERR_ICC_NoResponse;
    case IFD_ConnectError:  //            -11
        return ERR_ConnectError;
    case IFD_UnConnected:  //             -12
        return ERR_UnConnected;
    case IFD_BadCommand:  //              -13
        return ERR_BadCommand;
    case IFD_ParameterError:  //          -14
        return ERR_ParameterError;
    case IFD_CheckSumError:  //           -15
        return ERR_CheckSumError;
    case IFD_BadChipError:  //            -16
        return ERR_BadChipError;
    case IFD_NotFindDeivce:  //           -17
        return ERR_NotFindDeivce;
    case IFD_CanNotCreateHandle:  //      -18    
        return ERR_CanNotCreateHandle;
    default:
        return status;
    }
    return SUCCESS;
}

// 构造函数和接口函数实现
Tecsun_Adaptor::Tecsun_Adaptor()
{
    m_iStatus = NOT_INIT;
    m_isOpen = false;
    m_pSearch = nullptr;
}

Tecsun_Adaptor::~Tecsun_Adaptor()
{
    Close();
    m_isOpen = false;
}
// 公共接口
int Tecsun_Adaptor::Open(const Transport& tran)
{
    int ret = ICC_Reader_Open();
    m_isOpen = false;
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    m_isOpen = true;

    return m_iStatus;
}

int Tecsun_Adaptor::Close()
{
    if (!m_isOpen) {
        return SUCCESS;
    }
    int ret = ICC_Reader_Close();
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    m_isOpen = false;
    m_iStatus = ERR_DEVICE_NOT_OPEN;
    return SUCCESS;
}

bool Tecsun_Adaptor::IsOpen()
{
    if (!m_isOpen) {
        return false;
    }

    int ret = ICC_Reader_GetStatus(CARD_MAIN);
    return (ret != IFD_UnConnected && ret != IFD_ConnectError);
}

int Tecsun_Adaptor::Reset()
{
    return SUCCESS;
}

int Tecsun_Adaptor::GetStatus(int module, char *err)
{
    int ret = 0;
    switch (module) {
    case CT_SLOT_MAIN:  // 主卡座
        ret = ICC_Reader_GetStatus(CARD_MAIN);
        break;
    case CT_SLOT_PSAM1:  // PSAM1卡座
        ret = ICC_Reader_GetStatus(CARD_PSAM1);
        break;
    case CT_SLOT_PSAM2:  // PSAM2卡座
        ret = ICC_Reader_GetStatus(CARD_PSAM2);
        break;
    case CT_SLOT_RF:  // 非接存储卡卡座
        ret = ICC_Reader_GetStatus(CARD_NOTOUCH);
        break;
    default:
        break;
    }
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    return m_iStatus;
}

/**
  * 获取设备信息
  */
int Tecsun_Adaptor::GetDeviceInfo(DeviceInfo &devInfo)
{
    int ret = 0;
    // 获取厂家信息
    ret = ICC_Reader_Libinfo(devInfo.vendor);
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    // 终端设备号
    ret = ICC_Reader_GetDevID(devInfo.deviceId);
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    // 设备序列号
    ret = SerialNumber_Read(devInfo.serial);
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    // 获取lib版本
    ret = Get_Lib_Version(devInfo.libver);
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    ret = Get_Device_Version(devInfo.version);
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    return m_iStatus;
}
    /**
     * IO控制
     */
int Tecsun_Adaptor::IccIOCtrl(IOType type, int value)
{
    int ret = 0;
    switch (type) {
    case CT_ANTENNA_SWITCH:  // 天线开关
        ret = Rf_Set_Antenna(value);
        break;
    case CT_ANTENNA_POWER:  // 天线制式
        ret = Rf_Set_Type(value);
        break;
    case CT_BEEP:
        ret = ICC_Reader_Beep(value);
        break;
    case CT_SLOT_MAIN:  // 主卡座
        if (value != 0) {
            uchar retu[64];
            ret = ICC_Reader_PowerOn(CARD_MAIN, retu);
            printf("retu = %s\n", retu);
        } else {
            ret = ICC_Reader_PowerOff(CARD_MAIN);
        }
        break;
    case CT_SLOT_PSAM1: 
        if (value != 0) {
            uchar retu = 0;
            ret = ICC_Reader_PowerOn(CARD_PSAM1, &retu);
        } else {
            ret = ICC_Reader_PowerOff(CARD_PSAM1);
        }
        break;
    case CT_SLOT_PSAM2:
        if (value != 0) {
            uchar retu = 0;
            ret = ICC_Reader_PowerOn(CARD_PSAM2, &retu);
        } else {
            ret = ICC_Reader_PowerOff(CARD_PSAM2);
        }
        break;
    case CT_SLOT_RF:  // 非接卡
        if (value != 0) {
            uchar retu = 0;
            ret = ICC_Reader_PowerOn(CARD_NOTOUCH, &retu);
        } else {
            ret = ICC_Reader_PowerOff(CARD_NOTOUCH);
        }
        break;
    default:
        m_iStatus = ERR_DEVICE_NOT_SUPPORT;
        return m_iStatus;
    }
    CHECK_STATUS(ret == 0, ConvertStat(ret));
    return m_iStatus;
}
    /**
     * cpu命令
     */
int Tecsun_Adaptor::ApduCommand(IOType type, int len, uint8_t cmd[], uint8_t cmd_out[])
{
    CHECK_STATUS(len > 0, ERR_BadCommand);
    uchar slot = 0;
    switch (type) {
    case CT_SLOT_MAIN:  // 主卡座
        slot = CARD_MAIN;
        break;
    case CT_SLOT_PSAM1:  // PSAM1卡座
        slot = CARD_PSAM1;
        break;
    case CT_SLOT_PSAM2:  // PSAM2卡座
        slot = CARD_PSAM2;
        break;
    case CT_SLOT_RF:  // 非接存储卡卡座
        slot = CARD_NOTOUCH;
        break;
    default:
        m_iStatus = ERR_DEVICE_NOT_SUPPORT;
        return m_iStatus;
    }
    int ret = ICC_Reader_Application(slot, len, cmd, cmd_out);
    CHECK_STATUS(ret > 0, ConvertStat(ret));
    return ret;
}
    /**
     * 寻卡
     */
int Tecsun_Adaptor::CardSearch(int timeout, SearchResult *result)
{
    m_pSearch = result;
    m_iStatus = SUCCESS;
    return SUCCESS;
}
    /**
     * 停止寻卡
     */
int Tecsun_Adaptor::CardStopSearch()
{
    m_pSearch = nullptr;
    return m_iStatus;
}
    /**
     * 激活非存储卡
     */
int Tecsun_Adaptor::RfCardActive(RfCardInfo &cardInfo)
{
    int ret = Rf_Activate_Card(10, (unsigned char*)&cardInfo.type, (unsigned char*)cardInfo.uid);
    CHECK_STATUS(ret==0, ConvertStat(ret));
    return m_iStatus;
}
    /**
     * 非存储卡休眠
     */
int Tecsun_Adaptor::RfCardDormancy()
{
    int ret = Rf_Dormancy_Card();
    CHECK_STATUS(ret==0, ConvertStat(ret));
    return m_iStatus;
}

std::vector<std::string> StringSplit(const std::string& str, const char split)
{
    std::vector<std::string>  res;
    std::string strs = str + split;
    size_t pos = strs.find(split);

    while (pos != strs.npos) {
        std::string temp = strs.substr(0, pos);
        res.push_back(temp);
        strs = strs.substr(pos + 1, strs.size());
        pos = strs.find(split);
    }
    return res;
}

int strcpy_check(char buf[], const std::vector<std::string> &res, int index)
{
    if (index >= static_cast<int>(res.size())) {
        ICCREADER_HILOGE(ICCREADER_ADAPTOR, "index(%{public}d) >= size(%{public}d)",
            index, static_cast<int>(res.size()));
        return 0;
    }
    strncpy(buf, res[index].c_str(), res[index].length());
    ICCREADER_HILOGD(ICCREADER_ADAPTOR, "%{public}s -> %{public}s", res[index].c_str(), buf);
    return res[index].length();
}
    /**
     * 扫描数据
     */
int Tecsun_Adaptor::ScanData(const DeviceConfig& config, ResultData &result)
{
    ICCREADER_HILOGD(ICCREADER_ADAPTOR, "type = %{public}d", config.devType);
    result.type = config.devType;
    if (config.devType == DT_SECARD) {
        ICCREADER_HILOGD(ICCREADER_ADAPTOR, "findType = %{public}d",
            config.other.findType);
        char info[1024] = {0};
#ifdef  BUILD_WITH_ARM64
        int ret = iReadCardBasExt(config.other.findType, (char *)"/system/lib64/", info);
#else
        int ret = iReadCardBasExt(config.other.findType, (char *)"/system/lib/", info);
#endif

        CHECK_STATUS(ret == 0, ConvertStat(ret));
        std::vector<std::string> results = StringSplit(info, '|');
        strcpy_check(result.result.seCard.region_code, results, 0);
        strcpy_check(result.result.seCard.ssc_code, results, 1);
        strcpy_check(result.result.seCard.card_num, results, 2);
        strcpy_check(result.result.seCard.card_identy, results, 3);
        char name[128];
        int len = 0;
        len = strcpy_check(name, results, 4);
        if ((len = str_gbk2utf8(result.result.seCard.name, name, len)) < 0) {
            ICCREADER_HILOGE(ICCREADER_ADAPTOR, "gbk to utf8 failed, len = %{public}d, name = %{public}s",
                len, result.result.seCard.name);
        } else {
            ICCREADER_HILOGE(ICCREADER_ADAPTOR, "gbk to utf8 success, len = %{public}d, name = %{public}s",
                len, result.result.seCard.name);
        }

        strcpy_check(result.result.seCard.card_recover, results, 5);
        strcpy_check(result.result.seCard.version, results, 6);
        strcpy_check(result.result.seCard.issu_start, results, 7);
        strcpy_check(result.result.seCard.issu_end, results, 8);
        strcpy_check(result.result.seCard.term_no, results, 9);
        strcpy_check(result.result.seCard.term_device, results, 10);
    } else if (config.devType == DT_SYNCARD) {
        ICCREADER_HILOGD(ICCREADER_ADAPTOR, "photo = %{public}s", config.other.photo);
        strncpy(result.result.card.photo, config.other.photo, sizeof(config.other.photo));
        char info[512] = {0};
        char *buf = (char *)malloc(102*128*3*sizeof(char));
        memset(buf, 0, sizeof(102*128*3*sizeof(char)));
        Set_Path((char*)config.other.photo);
        Syn_Set_Configuration();
	    int ret = ICC_Reader_CertInfo(0, (char*)result.result.card.photo, buf, info);

        free(buf);
        CHECK_STATUS(ret >= 0, ConvertStat(ret));
        std::vector<std::string> results = StringSplit(info, '|');
        strcpy_check(result.result.card.name, results, 0);
        strcpy_check(result.result.card.sex, results, 1);
        strcpy_check(result.result.card.nation, results, 2);
        strcpy_check(result.result.card.birth, results, 3);
        strcpy_check(result.result.card.address, results, 4);
        strcpy_check(result.result.card.ID, results, 5);
        strcpy_check(result.result.card.issu_auth, results, 6);
        strcpy_check(result.result.card.issu_start, results, 7);
        strcpy_check(result.result.card.issu_end, results, 8);
    } else if (config.devType == DT_SCAN) {
        int ret = Get_Scanner(config.mode == 0? 0:1, config.timeout, result.result.buf);
        CHECK_STATUS(ret == 0, ConvertStat(ret));
    } else if (config.devType == DT_KEYBOARD) {
        int mode = 0x01;
        switch(config.mode) {
            case VOICE_NONE:
            case VOICE_PLEASE:
                mode = 0x01;
                break;
            case VOICE_NEW:
                mode = 0x02;
                break;
            case VOICE_NEWAGAIN:
                mode = 0x03;
                break;
            case VOICE_OLD:
                mode = 0x06;
                break;
        }
        int ret = Get_KeyBoard(mode, config.timeout, result.result.buf);
        CHECK_STATUS(ret == 0, ConvertStat(ret));
    } else if (config.devType == DT_MAGNETIC) {
        int ret = Get_MagneticTrack(config.mode, config.timeout, result.result.buf);
        CHECK_STATUS(ret == 0, ConvertStat(ret));
    } else {
        m_iStatus = ERR_DEVICE_NOT_SUPPORT;
    }
    return m_iStatus;
}

// 插件接口实现
std::shared_ptr<IAdaptor> CreateAdaptor()
{
    return std::make_shared<Tecsun_Adaptor>();
}
Transport GetAccess(ACCESS_MODE mode, const char *dev)
{
    Transport tran;
    tran.mode = mode;
    strncpy(tran.dev, dev, sizeof(tran.dev));
    tran.timeout = 3000;
    return tran;
}

static Plugin g_plugin = {
    .CreateAdaptor = CreateAdaptor,
    .GetAccess = GetAccess,
    .version = "1.0",
    .name = "Tecsun",
    .desc = "Tecsun Reader Adaptor 1.0",
    .id = 0x0501   //
};

PLUGIN_INIT(&g_plugin)
